package org.hyou.demos.msg.seri.util;

import java.io.IOException;

import org.msgpack.MessagePack;
import org.msgpack.template.Template;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * MessagePack数据处理工具类
 * 
 * @author Changshuo.Feng
 * @version 2.0.0 2015年4月28日 下午4:22:44 初始创建
 */
public abstract class MessagePackUtil {
    
    private static final Logger log = LoggerFactory.getLogger(MessagePackUtil.class);
    
    /**
     * MessagePack数据处理对象主类
     */
    private static MessagePack msgPack;
    
    static {
        msgPack = new MessagePack();
    }
    
    /**
     * <pre>
     * Registers {@link org.msgpack.template.Template} object for objects of
     * specified class. <tt>Template</tt> object is a pair of serializer and
     * deserializer for object serialization. It is generated automatically.
     * 
     * 版本修改历史记录：
     * 1) 2.0.0 2015年4月28日 下午4:32:36 Changshuo.Feng 初始创建
     * </pre>
     * 
     * @param type 数据对象类型
     */
    public static void register(Class<?> type) {
        msgPack.register(type);
    }
    
    /**
     * <pre>
     * Looks up a {@link org.msgpack.template.Template} object, 
     * which is serializer/deserializer associated by specified class.
     * 
     * 版本修改历史记录：
     * 1) 2.0.0 2015年4月28日 下午4:26:49 Changshuo.Feng 初始创建
     * </pre>
     * 
     * @param <T> 数据对应的对象类型
     * @param type 数据对象类型
     * @return 指定数据对象类对应的Template
     */
    public static <T> Template<T> lookup(Class<T> type) {
        return msgPack.lookup(type);
    }
    
    /**
     * <pre>
     * Looks up a {@link org.msgpack.template.Template} object, 
     * which is serializer/deserializer associated by specified class.
     * 先查找指定类型是否已经在MessagePack对象中注册，如果没有注册则先注册该对象类型并返回
     * 
     * 版本修改历史记录：
     * 1) 2.0.0 2015年4月28日 下午5:13:38 Changshuo.Feng 初始创建
     * </pre>
     * 
     * @param <T> 数据对应的对象类型
     * @param type 数据对象类型
     * @return 指定数据对象类对应的Template
     */
    public static <T> Template<T> lookupAndRegister(Class<T> type) {
        try {
            lookup(type);
        } catch(Exception e) {
            log.error(e.getMessage(), e);
            register(type);
        }
        
        return lookup(type);
    }
    
    /**
     * <pre>
     * Serializes specified object.
     * 
     * 版本修改历史记录：
     * 1) 2.0.0 2015年4月28日 下午4:36:15 Changshuo.Feng 初始创建
     * </pre>
     * 
     * @param <T> 数据对应的对象类型
     * @param object 要序列化的对象
     * @return 序列化后的数据
     * @throws IOException 序列化过程中可能抛出的异常
     */
    public static <T> byte[] write(T object) throws IOException {
        return msgPack.write(object);
    }
    
    /**
     * <pre>
     * Serializes specified object.
     * 
     * 版本修改历史记录：
     * 1) 2.0.0 2015年4月29日 上午11:33:57 Changshuo.Feng 初始创建
     * </pre>
     * 
     * @param <T> 数据对应的对象类型
     * @param object 要序列化的对象
     * @param tmpl 对象模板，用于序列化时转换为相应的对象类型
     * @return 序列化后的数据
     * @throws IOException 序列化过程中可能抛出的异常
     */
    public static <T> byte[] write(T object, Template<T> tmpl) throws IOException {
        return msgPack.write(object, tmpl);
    }
    
    /**
     * <pre>
     * Serializes specified object.
     * 序列化之前先进行被序列化对象的注册检查，如果对象没有注册则先注册再序列化
     * 
     * 版本修改历史记录：
     * 1) 2.0.0 2015年4月28日 下午4:48:46 Changshuo.Feng 初始创建
     * </pre>
     * 
     * @param <T> 数据对应的对象类型
     * @param object 被序列化的对象
     * @return 序列化结果数据
     * @throws IOException 序列化过程中可能抛出的异常
     */
    public static <T> byte[] writeAfterRegister(T object) throws IOException  {
        try {
            lookup(object.getClass());
        } catch(Exception e) {
            log.error(e.getMessage(), e);
            register(object.getClass());
        }
        
        return msgPack.write(object);
    }
    
    /**
     * <pre>
     * Deserializes byte array to object according to template.
     * 
     * 版本修改历史记录：
     * 1) 2.0.0 2015年4月28日 下午4:51:07 Changshuo.Feng 初始创建
     * </pre>
     * 
     * @param <T> 数据对应的对象类型
     * @param bytes 序列化后的数据对象值
     * @param tmpl 对象模板，用于反序列化时转换为相应的对象类型
     * @return 反序列化结果对象
     * @throws IOException 反序列化过程中可能抛出的异常
     */
    public static <T> T read(byte[] bytes, Template<T> tmpl) throws IOException {
        return msgPack.read(bytes, tmpl);
    }
    
}
